using Magiq.Databases.Delete;
using Magiq.Databases.Insert;
using Magiq.Databases.Query;
using Magiq.Databases.Update;
using Magiq.Delete;
using Magiq.Insert;
using Magiq.Query;
using Magiq.Support;
using Magiq.Update;

namespace Magiq.Databases
{
    public abstract class MagiqToDatabases : IMagiqProvider
    {
        protected abstract IDatabaseAdapter GetDatabaseAdapterFrom<T>(IUpdate<T> update);
        protected abstract IDatabaseAdapter GetDatabaseAdapterFromDestination<TSource, TDestination, TNew>(IInsert<TSource, TDestination, TNew> insert);
        protected abstract IDatabaseAdapter GetDatabaseAdapterFrom<T>(IDelete<T> delete);
        protected abstract IDatabaseAdapter GetDatabaseAdapterFrom<T>(IQuery<T> query);
        protected abstract IDatabaseAdapter GetDatabaseAdapterFrom<TSource, TDestination, TNew>(IInsert<TSource, TDestination, TNew> insert);

        public IDeleteStrategy GetDeleteStrategy<T>(IDelete<T> delete) where T : class
        {
            var databaseAdapter = GetDatabaseAdapterFrom(delete);
            return databaseAdapter == null ? null : new DatabaseDeleteStrategy<T>(databaseAdapter, delete);
        }

        public IInsertStrategy GetInsertStrategy<TSource, TDestination, TNew>(IInsert<TSource, TDestination, TNew> insert)
            where TDestination : class where TNew : class, TDestination, new()
        {
            var databaseAdapter = GetDatabaseAdapterFrom(insert);
            return databaseAdapter == null ? null : new DatabaseInsertStrategy<TSource, TDestination, TNew>(databaseAdapter, insert);
        }

        public IInsertDestination<TNew> GetInsertDestination<TSource, TDestination, TNew>(IInsert<TSource, TDestination, TNew> insertDestinationDefinition)
            where TNew : class, TDestination, new()
            where TDestination : class
        {
            var databaseAdapter = GetDatabaseAdapterFromDestination(insertDestinationDefinition);
            return databaseAdapter == null ? null : databaseAdapter.GetInsertDestination(insertDestinationDefinition);
        }

        public IQueryStrategy<T> GetQueryStrategy<T>(IQuery<T> query) where T : class
        {
            var databaseAdapter = GetDatabaseAdapterFrom(query);
            return databaseAdapter == null ? null : new DatabaseQueryStrategy<T>(databaseAdapter, query);
        }
        
        public IUpdateStrategy GetUpdateStrategy<T>(IUpdate<T> update) where T : class
        {
            var databaseAdapter = GetDatabaseAdapterFrom(update);
            return databaseAdapter == null ? null : new DatabaseUpdateStrategy<T>(databaseAdapter, update);
        }
    }
}